package hc.bre.cmn

import hc.bre.ComponentConfig
import hc.bre.cmn.struct.RuleResultStruct
import hc.bre.project.ProjectDefinition
import hc.bre.rest.cmn.SpringContext
import hc.bre.rest.manage.MainService
import hc.bre.runner.ScriptBlockRunner
import hc.bre.runner.ScriptLoaderRunner
import hc.bre.runner.ShellApplyRunner

import org.codehaus.groovy.control.CompilerConfiguration
import org.slf4j.*

@groovy.transform.CompileStatic
@groovy.transform.ToString(excludes=['project'],includeNames=true, includePackage = false)
class RuleDefinition{
	protected static final Logger _log = LoggerFactory.getLogger(RuleDefinition.class);
//	int rid				//unique identity, startup from 1
	String rname		//name for user
	String rpath 		//full location of the rule object
//	int rversion		//count to updated

	int rmaxid 			//max child item id
	String rmemo =''	//description by user
	String rtest ='{}'	//test sample for user

	String createdUser
	String createdTime
	String updatedUser
	String updatedTime

	public String getRtype() {
		Class clazz = this.getClass();
		return (clazz.getField("_config").get(clazz) as ComponentConfig).rtype;
	}

	RuleDefinition load(Map map)
	{
//		this.rid = map['rid'];
		this.rname = map['rname']
		this.rpath = map['rpath']
//		this.rversion = map['rversion']

		this.rmemo = map['rmemo']
		this.rtest = map['rtest']
		this.rmaxid = (map['rmaxid'] as Integer)?:0

		createdUser = map.createdUser
		createdTime = map.createdTime
		updatedUser = map.updatedUser
		updatedTime = map.updatedTime

		return this;
	}

	final public RuleDefinition load(String jsonText)
	{
		def map = hc.Util.jsonRead(jsonText);
		return load(map as Map);
	}

	public DiffResult<RuleDefinition> compareTo(RuleDefinition other) {
		DiffResult<RuleDefinition> result = new DiffResult<RuleDefinition>(self:this,other:other)

		if(this.updatedTime == other.updatedTime)
		{
			result.type = DiffType.identical;

		} else if(this.updatedTime > other.updatedTime)
		{
			result.type = DiffType.updated
		}
		else if(this.updatedTime < other.updatedTime)
		{
			result.type = DiffType.obsolote
		}

		return result;
	}

	static public RuleDefinition loadRuleDef(Map ruleDefMap) {
		String rtype = ruleDefMap['rtype']
		Class clazz = hc.bre.ComponentRegistry.get(rtype).ruleClass;
		RuleDefinition ruleDef = clazz.getConstructor().newInstance()
		return ruleDef.load(ruleDefMap);
	}

	@com.fasterxml.jackson.annotation.JsonIgnore
	ProjectDefinition project;
	public ProjectDefinition getProject()
	{
		if(project == null) {
			MainService service = SpringContext.applicationContext.getBean(MainService.class);
			project = service.loadProject(rpath.substring(0,rpath.indexOf('/')) +"/Main");
		};
		return project;
	}

	public void setProject(ProjectDefinition project)
	{
		this.project = project;
	}

	public <T extends RuleScriptBuilder> Class<T> scriptBuilderClass(){
		//		return RuleEmptyBuilder.class
		Class clazz = this.getClass();
		return (clazz.getField("_config").get(clazz) as ComponentConfig).builderClass;
	};

	public String buildRuleScript()
	{
		ScriptLoaderRunner.forRule(this).ruleClassScript;
		//		return scriptBuilderClass().getConstructor().newInstance().forRule(this).build();
	}

	public Class buildRuleClass(String classpath=null)
	{
		ScriptLoaderRunner.forRule(this,null,classpath).buildRuleClass();

		//		return new ScriptLoaderRunner(
		//				classpath:classpath,
		//				scriptBlock:buildRuleScript(),rpath:rpath).buildRuleClass();
	}

	Object buildRuleEvaluate(Map namedVariables,String classpath=null)
	{
		ScriptLoaderRunner.forRule(this,null,classpath).run(namedVariables);
		//		return new ScriptLoaderRunner
		//				(classpath:classpath,
		//				scriptBlock:buildRuleScript(),rpath:rpath).run(namedVariables);
	}
}
